package com.example.flower_shop.service.usr.impl;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.flower_shop.common.CacheObject;
import com.example.flower_shop.constans.ErrorMsg;
import com.example.flower_shop.entity.RoleEntity;
import com.example.flower_shop.entity.UserEntity;
import com.example.flower_shop.enums.RoleEnum;
import com.example.flower_shop.exception.AuthrizationException;
import com.example.flower_shop.exception.exception;
import com.example.flower_shop.mapper.RoleMapper;
import com.example.flower_shop.mapper.UserMapper;
import com.example.flower_shop.properties.MailProperties;
import com.example.flower_shop.service.usr.UserService;
import com.example.flower_shop.utils.CacheUtil;
import com.example.flower_shop.vo.auth.AuthRespVO;
import com.example.flower_shop.vo.role.RoleRespVO;
import com.example.flower_shop.vo.user.*;
import com.example.flower_shop.vo.usr.CodeReq;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.mail.MailSendException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author FuerHeart
 * @description 针对表【sys_user】的数据库操作Service实现
 * @createDate 2024-11-06 17:24:03
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity>
        implements UserService {

    @Resource
    private RoleMapper roleMapper;
    @Resource
    private JavaMailSender javaMailSender;
    @Resource
    private MailProperties mailProperties;
    @Resource
    private StoreOrderServiceImpl orderService;
    @Resource
    private UserMapper userMapper;

    @Override
    public AuthRespVO login(UserLogReqVO reqVO) {
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getUsername, reqVO.getUsername());
        UserEntity user = getOne(queryWrapper);
//        if (user == null || !BCrypt.checkpw(reqVO.getPassword(), user.getPassword())) {
//            throw new AuthrizationException();
//        }
        if (user == null || !reqVO.getPassword().equals(user.getPassword())) {
            throw new AuthrizationException();
        }
        if (!user.getStatus()) {
            throw new AuthrizationException("账号已被禁用");
        }
        List<RoleRespVO> roles = roleMapper.selectRoleByUserId(user.getId());
        if ("admin".equalsIgnoreCase(reqVO.getLoginType())) {
            if (!roles.stream().map(RoleRespVO::getName).toList().contains(RoleEnum.ADMIN.getRole())) {
                throw new AuthrizationException("用户不存在");
            }
        } else {
            if (!roles.stream().map(RoleRespVO::getName).toList().contains(RoleEnum.USER.getRole())) {
                throw new AuthrizationException("用户不存在");
            }
        }
        SaLoginModel saLoginModel = new SaLoginModel();
        boolean isVip = orderService.isVip(user.getId());
        saLoginModel.setExtra("isVip", isVip);
        StpUtil.login(user.getId(), saLoginModel);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        return AuthRespVO.of(tokenInfo.getTokenValue(), "", user.getId(), tokenInfo.getTokenTimeout());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(UserRegReqVO reqVO) {
        if (!reqVO.getPassword().equals(reqVO.getConfirmPassword())) {
            throw new exception("两次密码不一致!");
        }
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getUsername, reqVO.getUsername())
                .or().eq(UserEntity::getPhone, reqVO.getPhone())
                .or().eq(UserEntity::getEmail, reqVO.getEmail());
        queryWrapper.last("LIMIT 1");
        UserEntity user = getOne(queryWrapper);
        if (user != null && user.getUsername().equals(reqVO.getUsername())) {
            throw new exception("用户名已存在");
        }
        if (user != null && user.getPhone().equals(reqVO.getPhone())) {
            throw new exception("手机号已被其他用户绑定!");
        }
        if (user != null && user.getEmail().equals(reqVO.getEmail())) {
            throw new exception("邮箱已被其他用户绑定");
        }
        // 创建用户
        UserEntity entity = BeanUtil.toBean(reqVO, UserEntity.class);
//        entity.setPassword(BCrypt.hashpw(reqVO.getPassword(), BCrypt.gensalt()));
        boolean save = save(entity);
        if (!save) {
            throw new exception("注册失败!");
        }
        // 分配角色
        LambdaQueryWrapper<RoleEntity> roleQueryWrapper = new LambdaQueryWrapper<>();
        RoleEnum userRole = reqVO.getRole();
        roleQueryWrapper.eq(RoleEntity::getName, userRole.name());
        RoleEntity role = roleMapper.selectOne(roleQueryWrapper);
        if (role == null) {
            role = RoleEntity.builder()
                    .name(userRole.name())
                    .label(userRole.getLabel())
                    .build();
            int insert = roleMapper.insert(role);
            if (insert < 1) {
                throw new exception("分配角色失败!");
            }
        }
        boolean roleRel = roleMapper.insertUserRoleRel(entity.getId(), role.getId());
        if (!roleRel) {
            throw new exception("分配角色失败!");
        }
    }

    @Override
    public void updateUserInfo(UserReqVO reqVO) {
        long userId = StpUtil.getLoginIdAsLong();
        if (exists(new LambdaQueryWrapper<UserEntity>()
                .ne(UserEntity::getId, userId)
                .eq(UserEntity::getPhone, reqVO.getPhone()))) {
            throw new exception("手机号已被其他用户绑定!");
        }
        if (exists(new LambdaQueryWrapper<UserEntity>()
                .ne(UserEntity::getId, userId)
                .eq(UserEntity::getEmail, reqVO.getEmail()))) {
            throw new exception("邮箱已被其他用户绑定");
        }
        UserEntity user = getById(userId);
        if (user == null) {
            throw new exception(ErrorMsg.USER_NOT_EXIST);
        }
        UserEntity entity = BeanUtil.copyProperties(reqVO, UserEntity.class);
        entity.setId(userId);
        boolean update = updateById(entity);
        if (!update) {
            throw new exception(ErrorMsg.UPDATE_FAILED);
        }
    }

    @Override
    public UserRespVO getCurrentUserInfo() {
        long userId = StpUtil.getLoginIdAsLong();
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getId, userId);
        UserEntity user = getOne(queryWrapper);
        if (user == null) {
            throw new exception(ErrorMsg.USER_NOT_EXIST);
        }
        UserRespVO respVO = BeanUtil.toBean(user, UserRespVO.class);
        respVO.setVip(orderService.isVip(userId));
        return respVO;
    }

    @Override
    public void forgetPwd(ForgetPwdReq req) {
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getUsername, req.getUsername());
        UserEntity entity = getOne(queryWrapper);
        if (entity == null) {
            throw new exception(ErrorMsg.USER_NOT_EXIST);
        }
        CacheObject object = CacheUtil.get(entity.getEmail());
        long now = System.currentTimeMillis();
        if (object == null || now - object.getCreateTime() > object.getExpire() * 1000) {
            CacheUtil.remove(entity.getEmail());
            throw new exception("验证码失效!");
        }
        if (!object.getData().equals(req.getCode())) {
            throw new exception("验证码错误!");
        }
        if (!req.getPassword().equals(req.getConfirmPassword())) {
            throw new exception("两次输入的密码不一致!");
        }
        entity.setPassword(req.getPassword());
        boolean update = updateById(entity);
        if (!update) {
            throw new exception("修改密码失败!");
        }
    }

    @Override
    public void resetPwd(ResetPwdReq req) {
        if (!req.getConfirmPwd().equals(req.getNewPwd())) {
            throw new exception("两次输入的密码不一致!");
        }
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getId, StpUtil.getLoginIdAsLong());
        UserEntity user = getOne(queryWrapper);
        if (user == null) {
            throw new exception(ErrorMsg.USER_NOT_EXIST);
        }
//        if (!BCrypt.checkpw(req.getOldPwd(), user.getPassword())) {
//            throw new exception("密码错误!");
//        }
//        user.setPassword(BCrypt.hashpw(req.getNewPwd(), BCrypt.gensalt()));
        if (!req.getOldPwd().equals(user.getPassword())) {
            throw new exception("密码错误!");
        }
        user.setPassword(req.getNewPwd());
        boolean update = updateById(user);
        if (!update) {
            throw new exception("修改密码失败!");
        }
    }

    @Override
    public void getCode(CodeReq req) {
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getUsername, req.getUsername());
        UserEntity user = getOne(queryWrapper);
        if (user == null) {
            throw new exception(ErrorMsg.USER_NOT_EXIST);
        }
        if (req.getCodeType().equals("email")) {
            try {
                SimpleMailMessage mailMessage = new SimpleMailMessage();
                mailMessage.setTo(user.getEmail());
                mailMessage.setFrom(mailProperties.getUsername());
                mailMessage.setSubject("鲜花销售系统验证码");
                String code = RandomStringUtils.secure().nextNumeric(6);
                mailMessage.setText(code);
                javaMailSender.send(mailMessage);
                // 保存验证码到缓存 过期时间五分钟
                CacheUtil.put(user.getEmail(), code, 5 * 60);
            } catch (MailSendException e) {
                e.printStackTrace();
                throw new exception("验证码发送失败!");
            }
        }
    }
}




